<?php
namespace bdhert\PhpBitfieldModel;

use bdhert\PhpBitfieldModel\exception\InformatsException;

/**
 * 数据位域操作代理
 * Class Agent
 * @package bdhert\PhpBitfieldModel
 */
final class Agent {
    protected ?Model $model;

    public function __construct(Model &$model) {
        $this->model = &$model;
    }

    /**
     * 条件映射
     * @param array $conditions
     * @param null $operation
     * @param null $value
     * @return array[]|\array[][]
     */
    public function whereBefore($conditions = [], $operation = NULL, $value = NULL) {
        if (!is_array($conditions)) {
            if (is_null($operation)) throw new InformatsException('条件格式错误', 400);

            if (is_null($value)) {
                $conditions = [$conditions, '=', $operation];
            } else {
                $conditions = [$conditions, $operation, $value];
            }
        }

        if (!$this->isDimensions($conditions)) $conditions = [$conditions];

        $fields = $this->model->fields();
        foreach ($conditions as $condition_index => $condition) {
            if (3 !== count($condition)) throw new InformatsException('条件格式错误', 400);

            if (!is_numeric($condition[0])) {
                if (!isset($fields[$condition[0]])) {
                    unset($conditions[$condition_index]); continue;
                }

                [$cur_index, $mapped] = [0, []];
                foreach ($fields as $name => $length) {
                    if ($name === $condition[0]) {
                        $conditions[$condition_index][0] = $cur_index; break;
                    }
                    $cur_index++;
                }
            }
        }

        return [$conditions];
    }

    /**
     * 如上
     * @param array $conditions
     * @param null $operation
     * @param null $value
     * @return array[]|\array[][]
     */
    public function whereResetBefore($conditions = [], $operation = NULL, $value = NULL) {
        return $this->whereBefore($conditions, $operation, $value);
    }

    /**
     * 结果集合处理
     * @param array $list
     * @return mixed
     */
    public function get(array $list) {
        [$field_keys, $data] = [array_keys($this->model->fields()), []];
        foreach ($list as $v) {
            if (is_null($index = $v['index'] ?? NULL)) continue;

            $data_v['index'] = $index;
            foreach ($field_keys as $field_k => $field_v) {
                !is_null($val = $v[(string)$field_k] ?? NULL) && $data_v[$field_v] = $val;
            }

            $data[] = $data_v;
        }

        return $data;
    }

    /**
     * 新增数据字段映射
     * @param array $saves
     * @return array
     */
    public function insertBefore(array $saves) {
        $saves = $this->isDimensions($saves) ? $saves : [$saves];

        // 字段映射
        [$fields, $cur_index, $maps] = [$this->model->fields(), 0, []];
        foreach ($saves as $save) {
            $mapped = [];
            foreach ($fields as $name => $length) {
                if (!is_null($value = $save[$name] ?? ($save[$cur_index] ?? NULL))) $mapped[$cur_index] = $value;

                $cur_index++;
            }
            $cur_index = 0;

            !empty($mapped) && $maps[] = $mapped;
        }

        return [$maps];
    }

    /**
     * 更新数据字段映射
     * @param array $saves
     * @return array
     */
    public function updateBefore(array $saves) {
        if ($this->isDimensions($saves)) throw new InformatsException('保存格式错误', 400);

        // 字段映射
        [$fields, $cur_index, $mapped] = [$this->model->fields(), 0, []];
        foreach ($fields as $name => $length) {
            if (!is_null($value = $saves[$name] ?? ($saves[$cur_index] ?? NULL))) $mapped[$cur_index] = $value;

            $cur_index++;
        }

        return [$mapped];
    }

    /**
     * 自增字段映射
     * @param string $field
     * @param int $number
     * @return int[]
     */
    public function incrementBefore(string $field, int $number = 1) {
        $fields = $this->model->fields();
        if (false === ($field_index = array_search($field, array_keys($fields))))
            throw new InformatsException('字段不存在', 400);

        return [(int)$field_index, $number];
    }

    /**
     * 自减字段映射
     * @param string $field
     * @param int $number
     * @return int[]
     */
    public function decrementBefore(string $field, int $number = 1) {
        return $this->incrementBefore($field, $number);
    }

    /**
     * 新增持久化
     * @param string $string
     * @return bool
     */
    public function insert(string $string) {
        return $this->model->save($string);
    }

    /**
     * 更新持久化
     * @param string $string
     * @return bool
     */
    public function update(string $string) {
        return $this->model->save($string);
    }

    /**
     * 自增更新持久化
     * @param string $string
     * @return bool
     */
    public function increment(string $string) {
        return $this->model->save($string);
    }

    /**
     * 自减更新持久化
     * @param string $string
     * @return bool
     */
    public function decrement(string $string) {
        return $this->model->save($string);
    }

    /**
     * 置位持久化
     * @param string $string
     * @return bool
     */
    public function setbit(string $string) {
        return $this->model->save($string);
    }

    /**
     * 取消位持久化
     * @param string $string
     * @return bool
     */
    public function delbit(string $string) {
        return $this->model->save($string);
    }

    public function limit() {
        return $this->model;
    }

    public function where() {
        return $this->model;
    }

    public function whereReset() {
        return $this->model;
    }

    public function whereStrict() {
        return $this->model;
    }

    public function desc() {
        return $this->model;
    }

    public function asc() {
        return $this->model;
    }

    private function isDimensions(array $dimensions) {
        foreach ($dimensions as $dimension) {
            if(!is_array($dimension)) return false;
        }

        return true;
    }
}